package com.idanchuang.component.core;

import com.idanchuang.component.core.helper.EnvContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.*;
import java.util.Date;
import java.util.concurrent.*;

/**
 * @author yjy
 * Created at 2021/4/6 1:28 下午
 */
public final class Dc {

    private Dc() {}

    private static final Logger logger = LoggerFactory.getLogger(Dc.class);

    /** 公共线程池，可以用来执行一些实时性要求不高的异步任务，如果线程资源不足，将使用调用线程直接执行 */
    private volatile static ExecutorService COMMON_POOL;

    static {
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(availableProcessors, availableProcessors,
                1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(availableProcessors),
                (runnable) -> new Thread(runnable, "dc-common-pool"),
                new ThreadPoolExecutor.CallerRunsPolicy());
        // 允许释放核心线程，因为可能许多应用不会使用到这个线程池
        poolExecutor.allowCoreThreadTimeOut(true);
        COMMON_POOL = poolExecutor;
    }

    /**
     * 请求来源参数名
     */
    public static final String RPC_FROM_NAME = "rpc_from";
    public static final String RPC_FROM_API_NAME = "Rpc-From-Api";
    public static final String RPC_FROM_GROUP_NAME = "Rpc-From-Group";
    public static final String RPC_FROM_VERSION_NAME = "Rpc-From-Version";

    public static final String DEFAULT_RPC_FROM = "default";
    public static final String DEFAULT_RPC_FROM_API = "default";
    public static final String DEFAULT_RPC_FROM_GROUP = "default";
    public static final String DEFAULT_RPC_FROM_VERSION = "-1";
    /** 时光机偏移量 header名 */
    public static final String TIME_MACHINE_OFFSET_HEADER = "Dc-Tmo-Offset";
    /** 时光机偏移量 属性名 */
    public static final String TIME_MACHINE_OFFSET = "tmo";

    /** 用户id header名 */
    public static final String USER_ID_HEADER = "userId";
    /** 用户id 属性名 */
    public static final String USER_ID = "uid";

    /** 用户idCode header名 */
    public static final String USER_ID_CODE_HEADER = "userIdCode";
    /** 用户idCode 属性名 */
    public static final String USER_ID_CODE = "uidcode";

    /** 请求诊断类型 header名 */
    public static final String DIAG_HEADER = "Diag";
    /** 请求诊断类型 属性名 */
    public static final String DIAG = "diag";

    /** 压测专属服务实例 header名 */
    public static final String SPECIAL_INSTANCE_HEADER = "Pts-Si";
    /** 压测专属服务实例 属性名 */
    public static final String SPECIAL_INSTANCE = "ptsSi";

    /** 入口请求信息 属性名 */
    public static final String ORIGIN_REQUEST = "originReq";

    /**
     * @return 是否进行时间穿越
     */
    public static boolean isTimeTraveller() {
        String tmo = EnvContext.getAttribute(TIME_MACHINE_OFFSET);
        return tmo != null && !"0".equals(tmo);
    }

    /**
     * @return 时光机偏移量 (毫秒)
     */
    public static long tmoOffset() {
        String tmo = EnvContext.getAttribute(TIME_MACHINE_OFFSET);
        if (tmo == null) {
            return 0;
        }
        return Long.parseLong(tmo);
    }

    public static Clock tmoClock() {
        long offset = tmoOffset();
        if (offset == 0) {
            return Clock.systemDefaultZone();
        }
        return Clock.offset(Clock.systemDefaultZone(), Duration.ofMillis(offset));
    }

    /**
     * @return 当前时间戳
     */
    public static long currentTimeMillis() {
        long now = System.currentTimeMillis();
        long offset = tmoOffset();
        return now + offset;
    }

    /**
     * @return 当前时间
     */
    public static Date nowDate() {
        long now = currentTimeMillis();
        return new Date(now);
    }

    /**
     * @return 当前日期
     */
    public static LocalDate nowLocalDate() {
        return LocalDate.now(tmoClock());
    }

    /**
     * @return 当前时间
     */
    public static LocalTime nowLocalTime() {
        return LocalTime.now(tmoClock());
    }

    /**
     * @return 当前日期时间
     */
    public static LocalDateTime nowLocalDateTime() {
        return LocalDateTime.now(tmoClock());
    }

    /**
     * 自定义公共线程池
     * @param executorService 线程池
     */
    public synchronized static void setCommonPool(ExecutorService executorService) {
        ExecutorService old = Dc.COMMON_POOL;
        Dc.COMMON_POOL = executorService;
        old.shutdown();
    }

    /**
     * 获取当前公共线程池
     * @return ..
     */
    public static ExecutorService getCommonPool() {
        return Dc.COMMON_POOL;
    }

    /**
     * 使用公共线程池执行任务
     * ps.公共线程池，可以用来执行一些实时性要求不高的异步任务，如果线程资源不足，将使用调用线程直接执行
     * @param runnable 任务
     */
    public static void runAsync(Runnable runnable) {
        Dc.COMMON_POOL.execute(() -> {
            try {
                runnable.run();
            } catch (Exception e) {
                logger.error("Dc runAsync failed", e);
            }
        });
    }

    /**
     * 使用公共线程池执行任务
     * ps.公共线程池，可以用来执行一些实时性要求不高的异步任务，如果线程资源不足，将使用调用线程直接执行
     * @param callable 任务
     * @param <T> 返回对象类型
     * @return ..
     */
    public static <T> Future<T> runAsync(Callable<T> callable) {
        return Dc.COMMON_POOL.submit(() -> {
            try {
                return callable.call();
            } catch (Exception e) {
                logger.error("Dc runAsync failed", e);
                throw e;
            }
        });
    }

}
